package com.seven.thread;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author sevenDay
 * @classname SevenThreadPool
 * @description: 线程池的简单的封装
 * @date 2017/11/16
 */
public class SevenThreadPool {
    private static final Logger LOGGER = LoggerFactory.getLogger(SevenThreadPool.class);

    public static AtomicInteger automicIntger = new AtomicInteger(0);

    private ConcurrentHashMap<String,Object> taskContainer = new ConcurrentHashMap<>(16);

    /**
     * 线程池对象  线程池初始化方法
     *
     * corePoolSize 核心线程池大小----10
     * maximumPoolSize 最大线程池大小----30
     * keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit
     * TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES
     * workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(10)====10容量的阻塞队列
     * workQueue采用有界队列，能够控制和保证资源问题
     *             无界队列,不存在拒绝策略，资源问题无法保证,那么maximumPoolSize将失效，线程池中的线程最多就是corePoolSize个线程工作
     *             corePoolSize是否已经达到，需要锁的介入，因此我们应尽量让线程启动后线程池的大小就处于>=corePoolSize个数，提前预热
     *             无界队列，导致keepAliveTime/unit/maximumPoolSize失效，不存在拒绝；
                   随着任务的增长，线程数将固定在corePoolSize
     * threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂
     * rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时,
     * 即当提交第41个任务时(前面线程都没有执行完,此测试方法中用sleep(100)),
     * 任务会交给RejectedExecutionHandler来处理,超出线程池容量以及队列长度后拒绝任务的策略
     * 关于处理流程和策略的方案:
     *  提交任务，线程池中的线程数可以增长至corePoolSize，
     *  之后继续提交任务将暂存至队列中，
     *  如果队列满，则看是否能继续增长线程数至maximumPoolSize
     *  超出后将进行拒绝策略处理
     *  @ #See https://www.cnblogs.com/easycloud/p/3726089.html
     */
    private SevenThreadPoolExecutor pool = null;
    /**
     * 内存可见性的问题，避免创建多个线程池的问题
     */
    private volatile boolean flag=false;

    private static  SevenThreadPool threadPool = new SevenThreadPool();

    /**
     * 监控线程
     */
    private ThreadMonitor t = null;

    private SevenThreadPool(){}
    public static  SevenThreadPool getInstance(){
        return  threadPool;
    }
    public ThreadPoolExecutor getPool(){
        return pool;
    }
    /**
     *@method: initThread
     *@decription: 线程池的做法
     *@param: []
     *@author: dell
     *@version:
     *@exception:
     *@return: void
     */
    public synchronized void  initThread(int corePoolSize,int maximumPoolSize,int keepAliveTime,TimeUnit timeUnit,
                           SevenLinkedBlockingQueue sevenLinkedBlockingQueue,
                           SevenRejectedExecutionHandler sevenRejectedExecutionHandler){
        if (flag){
            return ;
        }else{
            pool =  new SevenThreadPoolExecutor(
                    corePoolSize,
                    maximumPoolSize,
                    keepAliveTime,
                    timeUnit,
                    sevenLinkedBlockingQueue,
                    new SevenThreadFactory(),
                    sevenRejectedExecutionHandler);
            flag=true;
            //启动监控线程
            t = new ThreadMonitor(pool,taskContainer);
            Thread thread = new Thread(t);
            thread.start();
            return ;
        }
    }
    public void destory() {
        if(pool != null) {
            pool.shutdown();
            ThreadMonitor.show=false;
        }
    }
    /**
     * 具有返回任务提交的线程
     * @param runnable
     * @return
     */
    public Future<?> submit(SevenRunnable runnable){
        final int taskId = automicIntger.incrementAndGet();
        runnable.setTaskId(taskId);
        if (StringUtils.isEmpty(runnable.getTaskName())){
            String name = UUID.randomUUID().toString().replace("-","");
            runnable.setTaskName(name);
        }
        addTask(taskId,runnable.getTaskName(),runnable);
        final Future<?> submit = pool.submit(runnable);
        return submit;
    }
    /**
     * 具有返回结果的提交任务
     * @param thread
     * @return
     */
    public Future<?> submit(SevenThread thread){
        final int taskId = automicIntger.incrementAndGet();
        thread.setTaskId(taskId);
        if (StringUtils.isEmpty(thread.getTaskName())){
            String name = UUID.randomUUID().toString().replace("-","");
            thread.setTaskName(name);
        }
        this.addTask(taskId,thread.getTaskName(),thread);
        Future<?> result = this.pool.submit(thread);
        return result;
    }

    /**
     * 具有返回结果的提交任务
     * @param call
     * @return
     */
    public SevenFutureTask<?> submit(SevenCallable<?> call){
        final int taskId = automicIntger.incrementAndGet();
        call.setTaskId(taskId);
        if (StringUtils.isEmpty(call.getTaskName())){
            String name = UUID.randomUUID().toString().replace("-","");
            call.setTaskName(name);
        }
        addTask(taskId,call.getTaskName(),call);
        final SevenFutureTask<?> result = (SevenFutureTask)this.pool.submit(call);
        return result;
    }
    /**
     * 没有返回值的提交任务
     * @param runable
     */
    public void execute(SevenRunnable runable){
        final int taskId = automicIntger.incrementAndGet();
        runable.setTaskId(taskId);
        if (StringUtils.isEmpty(runable.getTaskName())){
            String name = UUID.randomUUID().toString().replace("-","");
            runable.setTaskName(name);
        }
        addTask(taskId,runable.getTaskName(),runable);
        pool.execute(runable);
    }
    /**
     * 没有返回值的提交任务
     * @param thread
     */
    public void execute(SevenThread thread){
        final int threadIndex = automicIntger.incrementAndGet();
        thread.setTaskId(threadIndex);
        if (StringUtils.isEmpty(thread.getTaskName())){
            String name = UUID.randomUUID().toString().replace("-","");
            thread.setTaskName(name);
        }
        addTask(threadIndex,thread.getTaskName(),thread);
        this.pool.execute(thread);
    }

    /**
     * 获取task的任务的key
     * @param taskId
     * @param taskName
     * @return
     */
    /**
     * @descrp:添加任务到集合中去
     * @auther: sevenDay
     * @date: 2019/1/9 12:42
     * @param taskId :
     * @param taskName :
     * @param obj :
     * @return : void
     */
    private void  addTask(int taskId, String taskName, Object obj){

        String name = taskName;
        if (StringUtils.isEmpty(taskName)){
            name = UUID.randomUUID().toString().replace("-","");
        }
        String key =  taskId+"  "+ name;
        taskContainer.put(key,obj);
    }
    public ConcurrentHashMap<String,Object> getTaskContainer(){
        return taskContainer;
    }
}
